/*
 * Nettle zapgen code
 * (C) Nettle developers 2000-2002
 * $Id: zapgen,v 1.39 2004/04/02 06:31:59 archifishal Exp $
 */


#include "generic.h"
#include "globals.h"

#include "chardefn.h"
#include "messages.h"
#include "misc.h"
#include "nettle.h"
#include "wimp.h"
#include "wimputil.h"
#include "zapredraw.h"

#define ZR_CTRL 0

#define ZR_CTRL_FGBGCOLS 1
#define ZR_CTRL_END      2
#define ZR_CTRL_EXTEND   3
#define ZR_CTRL_MERGE    4
#define ZR_CTRL_FGCOL    6
#define ZR_CTRL_BGCOL    7
#define ZR_CTRL_CURSORM  8

#define REDRAW_FLAGS_MASK (NETTLE_FLAG_INVERTED | NETTLE_FLAG_SELECTED)

/* These used to be functions, and were fine in gcc... */
/* ...but Norcroft doesn't do inlines in C!! :-(      */

#define ZAP_WRITE_MULTIBYTE(write, chr)             \
{                                                   \
  *write++ = ZR_CTRL;                               \
  *write++ = ZR_CTRL_EXTEND;                        \
  *write++ = (char) (chr);                          \
  *write++ = (char) ((chr) >> 8);                   \
}

#define ZAP_WRITE_CHAR(write, input)                \
{                                                   \
  if (input->flags & NETTLE_FLAG_PLUS100)           \
  {                                                 \
    /* ZAP_WRITE_MULTIBYTE, but we know that the */ \
    /* top byte is 1, so we shortcut it */          \
    *write++ = ZR_CTRL;                             \
    *write++ = ZR_CTRL_EXTEND;                      \
    *write++ = (char) (input->chr);                 \
    *write++ = (char) (1);                          \
  }                                                 \
  else                                              \
  {                                                 \
    int c=input->chr;                               \
    *write++ = c;                                   \
    if (c == ZR_CTRL)                               \
      *write++ = 0;                                 \
  }                                                 \
}

static int *bitmaps_area=0;
static int bitmaps_area_number=0;


char * zapgen_code (int *output_buffer, struct term_char **input_line_offsets,
         int width, int first_line, int last_line, int session_flags,
         int selection_start_line, int selection_start_x,
         int selection_end_line, int selection_end_x)
{
  int *line_offsets = output_buffer;
  char *write = (char *)(line_offsets + last_line + 1);
  const struct term_char *input;
  int line_number = 0;
  bool selected = false;
  const struct term_char *startoffset, *endoffset;

  /* line_offsets -> list of offsets of lines (in the data block) */
  /* write -> next location at which to place data in the output buffer */

  if (first_line)
  {
    *write++ = ZR_CTRL;
    *write++ = ZR_CTRL_END;
  }

  /* Why isn't this lot a tautology? */
  if (selection_start_line > selection_end_line)
  {
    int tmp = selection_start_line;
    selection_start_line = selection_end_line;
    selection_end_line = tmp;
    tmp = selection_start_x;
    selection_start_x = selection_end_x;
    selection_end_x = tmp;
  }
  else if (selection_start_line == selection_end_line)
  {
    if (selection_start_x > selection_end_x)
    {
      int tmp = selection_start_x;
      selection_start_x = selection_end_x;
      selection_end_x = tmp;
    }
    else if (selection_start_x == selection_end_x)
    {
      selection_start_x = selection_end_x = -1;
    }
  }
  /* End tautological moan */

  if (selection_start_line < first_line && selection_end_line >= first_line)
    selected = true;

  startoffset = input_line_offsets[selection_start_line]+selection_start_x;
  endoffset = input_line_offsets[selection_end_line]+selection_end_x;

  for (; line_number < last_line; line_number++)
  {
    int loop = width;
    int current_fg = redraw.r_for;
    int current_bg = redraw.r_bac;

    input=input_line_offsets[line_number];

    if (line_number < first_line)
    {
      /* if not in the window, mark the line as blank and move on */
      /* (this is done by pointing the line at the previous EOL marker) */
      *line_offsets++ = write - 2 - (char *) output_buffer;
      continue;
    }

    *line_offsets++ = write - ((char *) output_buffer);

    for (; loop; --loop)
    {
      register char colour_type;
      char fg = input->fg;
      char bg = input->bg;
      bool invert=false;

      /* swap foreground and background if inverted or selected or inverse video etc. */
      if (input->flags & NETTLE_FLAG_INVERTED)
        invert=NOT(invert);

      if (input == startoffset || input == endoffset)
        selected=NOT(selected);

      if (selected)
        invert=NOT(invert);

      if (session_flags & NETTLE_OTHER_REVERSE_VIDEO)
        invert=NOT(invert);

      if (invert)
      {
        fg ^= bg;
        bg ^= fg;
        fg ^= bg;
      }

      if (selected)
      {
        if (fg==bg)
          fg=15-bg;
      }

      if ((input->flags & NETTLE_FLAG_BLINK) && blinking && cursor_state)
        fg = bg;

      if (fg != current_fg || bg != current_bg)
      {
        *write++ = ZR_CTRL;
        colour_type = (fg == current_fg) ? ZR_CTRL_BGCOL /* bg only if fg unchanged */
                : (bg == current_bg) ? ZR_CTRL_FGCOL /* fg only if bg unchanged */
                :                      ZR_CTRL_FGBGCOLS; /* both if neither unchanged */
        *write++ = colour_type;

        if (colour_type != ZR_CTRL_BGCOL)
          *write++ = fg;

        if (colour_type != ZR_CTRL_FGCOL)
          *write++ = bg;

        /* save the current settings */
        current_fg = fg;
        current_bg = bg;
      }

      if (input->flags & NETTLE_FLAG_CURSOR)
      {
        /* drawing the cursor... */
        int blink;
        if (cursor_blink)
          blink = (cursor_state || input->flags & NETTLE_FLAG_NO_INPUT) ? bg : fg;
        else
          blink = bg;

        *write++ = ZR_CTRL;
        *write++ = ZR_CTRL_MERGE;   /* character merge */
        *write++ = blink;           /* foreground colour */
        *write++ = ((blink & 2) ? 0 : 7) | (8 & ~blink);
                    /* contrasting background, inverted bright */
        ZAP_WRITE_CHAR(write, input);

        if (input->flags & NETTLE_FLAG_NO_INPUT)
        {
          ZAP_WRITE_MULTIBYTE(write, 0x101); /* square/hatched cursor */
        }
        else
        {
          ZAP_WRITE_MULTIBYTE(write, 0x100); /* block/underline cursor */
        }
      }
      else
      {
        if (input->flags & NETTLE_FLAG_UNDERLINE)
        {
          *write++ = ZR_CTRL;
          *write++ = ZR_CTRL_MERGE;   /* character merge */
          *write++ = fg;              /* foreground colour */
          *write++ = fg;              /* background colour */
          ZAP_WRITE_CHAR(write, input);
          ZAP_WRITE_MULTIBYTE(write, 0x11D); /* The underline itself! */
        }
        else
        {
          ZAP_WRITE_CHAR(write, input);
        }
      }

      input++;
    }

    *write++ = ZR_CTRL;
    *write++ = ZR_CTRL_END;     /* end of line marker */
  }
  *line_offsets = 0;

  return write;                 /* return ptr to the first unused byte */
}


void allocate_zapredraw_area(int terminal_size_x, int terminal_size_y, int scrollback)
{
  int size_of_row_pointers = ( terminal_size_y+scrollback+1 ) * 4;
  int size_of_one_char     = 4  /* A colour change */
                           + 4  /* Multibyte char */
                           + 5+3; /* Underline (merge+multibyte)*/
  int size_of_body         = ( terminal_size_x*(terminal_size_y+1) ) * size_of_one_char;
  int size_of_eols         = ( terminal_size_y+1 )*2;
  int size_of_cursor       = 8; /* 4bytes mb cursor, 4 bytes control */

  int calculate_new_size   = size_of_row_pointers + size_of_body + size_of_eols + size_of_cursor;

  if (size_of_zapredraw_area < calculate_new_size)
  {
    int *new_zapredraw_area;

    size_of_zapredraw_area = calculate_new_size;

    if (dynamic_areas_available())
    {
      char string[]="Nettle ZapRedraw area";

      if (zapredraw_area_number!=0)
      {
        _swi(OS_DynamicArea, _INR(0,1), 1, zapredraw_area_number);
      }

      _swi(OS_DynamicArea, _INR(0,8)|_OUT(1)|_OUT(3), 0, -1, size_of_zapredraw_area,
                           -1, 0x80, size_of_zapredraw_area, 0, -1, string, &zapredraw_area_number,
                           &new_zapredraw_area);
    }
    else
    {
      new_zapredraw_area = realloc(zapredraw_area, size_of_zapredraw_area);
    }

    if (!new_zapredraw_area)
    {
      generror("Nettle has run out of memory in a nasty place. Sometime this will be fixed better.\n", false);
      assert(false);
    }

    zapredraw_area = new_zapredraw_area;
  }
}


void lose_zapredraw_area(void)
{
  if (dynamic_areas_available())
  {
    if (zapredraw_area_number!=0)
    {
      _swi(OS_DynamicArea, _INR(0,1), 1, zapredraw_area_number);
    }
  }
  else
  {
    free(zapredraw_area);
  }
}


/*
 * Description:  Update the cursors in a given font_area
 * Parameters:   font_area-> the area, as returned from load_font
 * Returns:      none
 * Note:         Will also update all the other special characters;
 *               this is not intentional and should be replaced with
 *               /just/ the cursors being updated.
 */
void update_cursors(int *font_area)
{
  int width  = font_area[2];
  int height = font_area[3];
  int char_size = ((width+ 7) & ~7)*height/8;

  /* fill in graphics chars */
  define_zap_chars(font_area+8, char_size, width, height);
}


int *load_font(char *font)
{
  char string[5]="ZFLK";
  int *zap_load_area = 0;
  int width;
  int height;
  int last_char;
  int first_char;
  int char_size;
  FILE *file_handle=0;
  char file_end[256];
  char file_start[256];
  char file_name[1024];
  int object_type;

  get_system_variable(file_name,"ZapFonts$Path",sizeof(file_name));
  if (strlen(file_name)!=0)
  {
    strcpy(file_start,"ZapFonts:");
  }
  else
  {
    strcpy(file_start,"<Nettle$Dir>.Fonts.");
  }

  strcpy(file_end, font);

  /* if string is ZFLK, then this is a redirection font */
  while (strcmp(string,"ZFLK")==0)
  {
    sprintf(file_name,"%s%s",file_start,file_end);

    /* if it's there, what sort of object is it */
    if (_swix(OS_File, _INR(0,1)|_OUT(0), 17, file_name, &object_type)==0)
    {
      if (object_type == 0)
      {
          strcpy(string,"");
      }
      else if (object_type == 2)
      {
        /* If it's a directory, plonk .0 on the end */
        strcat(file_end,".0");
        strcat(file_name,".0");

        /* and pretend it's a file */
        object_type = 1;
      }

      if (object_type == 1)
      {
        file_handle=fopen(file_name,"rb");

        if (file_handle != NULL)
        {
          fread(&string[0],1,5,file_handle);
          string[4]='\0';

          /* if it's redirection then */
          if (strcmp(string,"ZFLK")==0)
          {
            size_t chrs;

            /* get the redirection font */
            chrs = fread(&file_end[0], 1, sizeof(file_end)-1, file_handle);
            file_end[chrs]='\0';

            fclose(file_handle);
          }
        }
      }
    }
    else
    {
      strcpy(string,"");
    }
  }

  if (file_handle==0)
  {
    /* if we didn't find a font, use Nettle's internal ones */
    /* (This may not be necessary if it uses <Nettle$Dir>.Fonts from above, but leave it for */
    /* now) */

    if (eig.y >1)
      strcpy(file_name,"<Nettle$Dir>.Fonts.08x08.0");
    else
      strcpy(file_name,"<Nettle$Dir>.Fonts.08x16.0");
    file_handle=fopen(file_name,"rb");
  }

  assert(file_handle);

  fseek(file_handle,8,SEEK_SET);

  /* Get font information */
  fread((char *) &width, 1, 4, file_handle);
  fread((char *) &height, 1, 4, file_handle);
  fread((char *) &first_char, 1, 4, file_handle);
  fread((char *) &last_char, 1, 4, file_handle);

  /* Set real character size (will be needed to implement graphics characters) */
  char_size=((width+ 7) & ~7)*height/8;

  if (first_char > 256)
    first_char = 256;
  if (last_char > 256)
    last_char = 256;

  if (first_char != last_char)
  {
    zap_load_area=malloc(char_size*(0x100+EXTRA_ZAP_CHARS)+0x20);
    if (!zap_load_area)
    {
      /* FIXME: This might leave DAs lying about */
      generror(lookup_inbuffer("OutOfMem"), false);
      assert(false);
    }

    memset (zap_load_area, 0, char_size*(0x100+EXTRA_ZAP_CHARS) + 0x20);
    fseek(file_handle,0,SEEK_SET);
    fread ((char *) zap_load_area, 1, 0x20, file_handle);
    fread ((char *) zap_load_area + 0x20 + first_char * char_size,
           1, (last_char - first_char) * char_size, file_handle);
  }

  if (ferror (file_handle) || first_char == last_char)
  {
    /* Eek! Fall back on system font... */
    width = 8;
    char_size = height = (eig.y > 1) ? 8 : 16;
    zap_load_area = realloc (zap_load_area, char_size * (0x100+EXTRA_ZAP_CHARS) + 0x20);
    if (!zap_load_area)
    {
      /* FIXME: This might leave DAs lying about */
      generror(lookup_inbuffer("OutOfMem"), false);
      assert(false);
    }

    zap_load_area[2] = width;
    zap_load_area[3] = height;
    zap_load_area[4] = first_char = 32;
    zap_load_area[5] = last_char = 32;
    assert (zap_load_area != NULL);
  }

  fclose(file_handle);

  /* fill in graphics chars */
  define_zap_chars(zap_load_area+8, char_size, width, height);

  /* fill in some undefined characters in range 0x00-0xFF*/
  define_zap_undef_chars (zap_load_area+8, first_char, last_char,
                          char_size, width, height);

  zap_load_area[4]=0;
  zap_load_area[5]=0x100+EXTRA_ZAP_CHARS;

  return zap_load_area;
}


/***************************
 * Zap fonts menu creation *
 ***************************/

static int zapfont_depth = 0;            /* Nesting level */
static int *zapfont_menu[8] = {0};        /* Menu data */
static char *zapfont_menu_entries[8] = {0};    /* Menu data */

static char font_path[512];
static int font_path_base;


bool
read_zap_font_selection (const int *selection, char *string, int length)
{
  /* returns true if the object is a file or contains a file named "0" */
  int loop = 0;
  int sum = 0;
  int type;
  int reason;

  *string = 0;
  for (;;)
  {
    const char *item = (char *) zapfont_menu[loop][7+3+6*selection[loop]];
    sum += strlen (item) + (sum > 0);
    if (sum >= length - 2)
      break;            /* silently truncate */

    strcat (string, item);
    if (selection[++loop] == -1)
      break;

    strcat (string, "."); /* more to do... */
  }

  if (string != font_path + font_path_base)
  {
    font_path[font_path_base] = '\0';
    reason = 13;
  }
  else
  {
    string = font_path;
    reason = 17;
  }

  /* Return true if the extracted name points to a file */
  if (_swix (OS_File, _INR(0,1) | _IN(4) | _OUT(0),
         reason, string, font_path, &type))
      return false;

  if (type == 1)
    return true;

  /* Append ".0" and return true if it points to a file; else return false */
  strcat (string, ".0");
  if (_swix (OS_File, _INR(0,1) | _IN(4) | _OUT(0),
         reason, string, font_path, &type))
    type = 0;

  string[strlen (string) - 2] = '\0';
  return (type == 1) ? true : false;
}


static int
menu_strcoll (const void *s1, const void *s2)
{
  return strcoll (*((const char **)s1 + 3), *((const char **)s2 + 3));
}


static bool
create_zap_font_menu_internal (int **menu_block_p, char **menu_entries_p,
                   bool root_menu)
{
  int *menu_block = 0;
  char *menu_entries;
  int allocated = 1024;
  int items = 0;
  int entry_offset = 0;
  int dir_offset = 0;

  /* Hit the maximum menu depth? */
  if (zapfont_depth == 8)
    return false;

  menu_entries = malloc (allocated);
  if (!menu_entries)
    return false;

  /* Build the menu... */
  do
  {
    struct
    {
      int load, exec, length, attr, object_type;
      char name[256];
    } dir_entry;
    int count;
    _kernel_oserror *error;

    error = _swix (OS_GBPB, _INR(0,6) | _OUTR(3,4),
           10, font_path, &dir_entry, 1, dir_offset, sizeof (dir_entry), 0,
           &count, &dir_offset);
    if (error)
    {
      generror (error->errmess, false);
      goto done;
    }

    /* if we have an object and it's a directory (root menu) or a directory
     * or a file (submenu), process it */
    if (count && (dir_entry.object_type & (root_menu ? 2 : 3)))
    {
      /* got a directory entry - buffer it */
      if (strcmp("CVS", dir_entry.name) != 0)
      {
        if ( (entry_offset + strlen (dir_entry.name) + 2) >= allocated)
        {
          menu_entries = realloc (menu_entries, allocated += 1024);
          if (!menu_entries)
            goto done;
        }
        menu_entries[entry_offset++] = (char) dir_entry.object_type;
        strcpy (menu_entries + entry_offset, dir_entry.name);
        entry_offset += strlen (menu_entries + entry_offset) + 1;
        items++;
      }
    }
  } while (dir_offset != -1);

  if (items)
  {
    /* we know how much memory we need - now build the menu */
    int index_loop = 7;
    int loop;

    /* free up a small amount of memory */
    menu_entries = realloc (menu_entries, entry_offset);
    if (!menu_entries)
      goto done;

    /* claim space for the menu */
    menu_block = malloc (28 + 24 * items);
    if (!menu_block)
      goto done;

    /* set up the menu header */
    if (root_menu)
    {
      lookup ("MenuFont", (char *) menu_block, 12);
    }
    else
    {
      /* use the leafname as the title */
      char *dot = strrchr (font_path, '.');
      if (!dot)
        dot = strrchr (font_path, ':');
      strcpy ((char *) menu_block, dot + 1);
    }
    menu_block[3] = 0x70207; /* standard menu colours */
    menu_block[4] = 0;
    menu_block[5] = 44;
    menu_block[6] = 0;

    /* now add the menu items */
    entry_offset = 0;
    for (loop = 0; loop < items; ++loop)
    {
      int length = strlen (menu_entries + entry_offset + 1);

      if (menu_entries[entry_offset++] & 2)
      {
        menu_block[index_loop++] = 8;        /* menu warn bit */
        menu_block[index_loop++] = MENU_ZAPFONTLIST;
      }
      else
      {
        menu_block[index_loop++] = 0;
        menu_block[index_loop++] = -1;
      }

      menu_block[index_loop++] = WIMP_ICON_FGCOL(7) | WIMP_ICON_VCENT_BIT |
                     WIMP_ICON_FILLED_BIT | WIMP_ICON_TEXT_BIT |
                     WIMP_ICON_INDIRECTED_BIT;
      menu_block[index_loop++] = (int) (menu_entries + entry_offset);
      menu_block[index_loop++] = (int) (menu_entries + entry_offset + length);
      menu_block[index_loop++] = length + 1;
      entry_offset += length + 1;
    }

    /* sort the entries (in case the list was read from, e.g., NFS) */
    qsort (menu_block + 7, (index_loop - 7) / 6, 6 * sizeof (int), menu_strcoll);

    menu_block[index_loop - 6] |= 128;    /* last entry */

    /* done: return the pointers */
    *menu_block_p = menu_block;
    *menu_entries_p = menu_entries;

    return true;
  }

  /* Error or no menu entries */
done:
  free (menu_block);
  free (menu_entries);
  return false;
}


bool create_zap_font_menu(int window_handle, int icon_handle)
{
  get_system_variable(font_path, "ZapFonts$Path", sizeof (font_path));
  strcpy(font_path, *font_path ? "ZapFonts:" : "NettleFonts:");
  font_path_base = strlen (font_path);

  if(create_zap_font_menu_internal (zapfont_menu, zapfont_menu_entries, true))
  {
    zapfont_depth = 1;
    create_menu_by_icon (zapfont_menu[0], window_handle, icon_handle);
    return true;
  }
  return false;
}


void create_zap_font_submenu (const int *selection, struct coords open_at)
{
  int loop;

  /* get the directory path (from the menu) */
  if (font_path[font_path_base - 1] == ' ')
    font_path[font_path_base - 1] = '.';
  read_zap_font_selection (selection, font_path + font_path_base,
               sizeof (font_path) - font_path_base);

  loop = 0;
  while (selection[loop] != -1)
    loop++;

  zapfont_depth = loop;
  while (loop < 8)
  {
    free (zapfont_menu[loop]);
    free (zapfont_menu_entries[loop]);
    zapfont_menu[loop] = 0;
    zapfont_menu_entries[loop] = 0;
    loop++;
  }

  if (create_zap_font_menu_internal (zapfont_menu + zapfont_depth,
                     zapfont_menu_entries + zapfont_depth,
                     false))
  {
    _swi(Wimp_CreateSubMenu, _INR(1,3), zapfont_menu[zapfont_depth++],
                    open_at.x, open_at.y);
  }
}


void reopen_zap_font_menu (void)
{
  _swi (Wimp_CreateMenu, _INR(1,3), zapfont_menu[0], 0, 0);
}


void delete_zap_font_menu (void)
{
  int loop;
  /* make sure that we've freed any memory that we may have allocated */
  for (loop = 7; loop >= 0; loop--)
  {
    free (zapfont_menu[loop]);
    free (zapfont_menu_entries[loop]);
    zapfont_menu[loop] = 0;
    zapfont_menu_entries[loop] = 0;
  }
  zapfont_depth = 0;
}

void recache_bitmaps(void)
{
  int *zap_font_used;
  int mem_required;
  int a;
  int b;

  /* work out which font we should be using */
  zap_font_used = (eig.y <= 1) ? zap_font_area : zap_lowres_font_area;

  _swi(ZapRedraw_ReadVduVars, _IN(1), &redraw);

  mem_required=((zap_font_used[2]+7) & ~7)*zap_font_used[3]*(zap_font_used[5]-zap_font_used[4]);

  switch (redraw.r_bpp)
  {
    case 0:mem_required/=8;break;
    case 1:mem_required/=4;break;
    case 2:mem_required/=2;break;
    case 4:mem_required*=2;break;
    case 5:mem_required*=4;break;
  }

  /* Reallocate the bitmaps area */
  if (dynamic_areas_available())
  {
    if (bitmaps_area_number==0)
    {
      const char string[]="Nettle bitmaps area";

      /* Currently, in a 32bpp mode, with the biggest available ZapFont (14x12.Luc)
         we can use up to 444K of space, so we set a 1MB max area size here.  If we
	 don't, then the OS_ChangeDynamicArea below will die and we will all be upset */

      _swi(OS_DynamicArea, _INR(0,8)|_OUT(1)|_OUT(3), 0, -1, mem_required, -1, 0x80,
                           1024*1024 /* allow room for loading bigger fonts later */,
                           0, -1, string, &bitmaps_area_number, &bitmaps_area);
    }
    else
    {
      int current_size;

      _swi(OS_DynamicArea, _INR(0,1)|_OUT(2), 2, bitmaps_area_number, &current_size);

      if (mem_required-current_size!=0)
      {
        _swi(OS_ChangeDynamicArea, _INR(0,1), bitmaps_area_number, mem_required-current_size);
      }
    }
  }
  else
  {
    int *tmp=realloc(bitmaps_area, mem_required);
    if (tmp)
    {
      bitmaps_area=tmp;
    }
    else
    {
      generror("Nettle has run out of memory in a bad way. Sometime this will be fixed better.\n", false);
      assert(false);  /* Duh. Panic! */
    }
  }

  redraw.r_flags=0;
  redraw.r_charw=zap_font_used[2];
  redraw.r_charh=zap_font_used[3];
  redraw.r_caddr=bitmaps_area;

  _swi(ZapRedraw_CachedCharSize, _INR(0,3)|_OUTR(2,3),
                                 redraw.r_bpp, 0, redraw.r_charw, redraw.r_charh, &a, &b);

  redraw.r_cbpl=a;
  redraw.r_cbpc=b;
  redraw.r_linesp=0;

  _swi(ZapRedraw_ConvertBitmap, _INR(1,4), &redraw, 0, 0x100+EXTRA_ZAP_CHARS,
                                ((char *) zap_font_used)+32);

  redraw.r_palette=zap_palette;

  _swi(ZapRedraw_CreatePalette, _INR(0,4), 2, &redraw, palette, zap_palette, 16);

  redraw.r_for=7;
  redraw.r_bac=0;
}


void lose_bitmaps(void)
{
  if (dynamic_areas_available())
  {
    if (bitmaps_area_number!=0)
    {
      _swi(OS_DynamicArea, _INR(0,1), 1, bitmaps_area_number);
    }
  }
  else
  {
    free(bitmaps_area);
  }
}
